﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Xna.Framework.Content;
using DARE.Properties;

namespace DARE
{
    [AttrTypeDependentSerializable(typeof(DARE.Save.DataStructures.CEffectData))]
    public class CEffect
    {
        #region fields

        protected bool lighteningEnabled;
        protected Vector4 emissiveLight;
        protected Vector4 ambientLight;
        protected Vector3 directionalLight1Direction;
        protected Vector4 directionalLight1Diffuse;
        protected Vector4 directionalLight1Specular;
        protected Vector3 directionalLight2Direction;
        protected Vector4 directionalLight2Diffuse;
        protected Vector4 directionalLight2Specular;
        protected Vector3 directionalLight0Direction;
        protected Vector4 directionalLight0Diffuse;
        protected Vector4 directionalLight0Specular;
        protected CBasicEffect m_effect;

        #endregion

        #region properties

        public CBasicEffect BasicEffect { get { return m_effect; } }
        public Effect Effect
        {
            get
            {
                if (m_effect != null)
                    return m_effect.Effect;
                return null;
            }
        }
        public bool PerPixelLighteningEnabled { get; set; }
        public bool UseSceneParameters { get; set; }
        public bool IsAnimationActive { get; set; }
        public bool IsDecalsActive { get; set; }
        public Vector3 EyePosition { get; set; }
        public bool IsMultiTexturingActive { get; set; }

        #region multitexturing

        public Vector2 ColorMapTiles1 { get; set; }
        public Vector2 ColorMapOffset1 { get; set; }
        public Texture2D ColorMap1 { get; set; }
        public Vector2 ColorMapTiles2 { get; set; }
        public Vector2 ColorMapOffset2 { get; set; }
        public Texture2D ColorMap2 { get; set; }
        public Vector2 ColorMapTiles3 { get; set; }
        public Vector2 ColorMapOffset3 { get; set; }
        public Texture2D ColorMap3 { get; set; }
        public Vector2 MultiTexturingMapTiles { get; set; }
        public Vector2 MultiTexturingMapOffset { get; set; }
        public Texture2D MultiTexturingMap { get; set; }

        #endregion

        #region decals

        public Matrix DecalsProjectorMatrix { get; set; }
        /*public Vector3 DecalsProjectorPosition { get; set; }
        public Vector3 DecalsProjectorDirection { get; set; }
        public float DecalsProjectorSize { get; set; }
        public Vector3 DecalsProjectorUpVector { get; set; }
        public Matrix DecalsProjectorProjection { get; set; }*/
        public Texture2D DecalsMap { get; set; }

        #endregion

        #region lightening

        public float Brighteness { get; set; }

        public bool LighteningEnabled { get { return lighteningEnabled; } set { lighteningEnabled = value; } }

        public Color AmbientLightColor
        {
            get
            {
                return new Color(ambientLight.X, ambientLight.Y, ambientLight.Z);
            }
            set
            {
                ambientLight.X = value.R;
                ambientLight.Y = value.G;
                ambientLight.Z = value.B;
            }
        }

        public float AmbientLightIntensity
        {
            get
            {
                return ambientLight.W;
            }
            set
            {
                ambientLight.W = value;
            }
        }

        public Color EmissiveLightColor
        {
            get
            {
                return new Color(emissiveLight.X, emissiveLight.Y, emissiveLight.Z);
            }
            set
            {
                emissiveLight.X = value.R;
                emissiveLight.Y = value.G;
                emissiveLight.Z = value.B;
            }
        }

        public float EmissiveLightIntensity
        {
            get
            {
                return emissiveLight.W;
            }
            set
            {
                emissiveLight.W = value;
            }
        }

        public Vector3 DirectionalLight1Direction
        {
            get { return directionalLight1Direction; }
            set { directionalLight1Direction = value; }
        }

        public Color DirectionalLight1DiffuseColor
        {
            get { return new Color(directionalLight1Diffuse.X, directionalLight1Diffuse.Y, directionalLight1Diffuse.Z); }
            set
            {
                directionalLight1Diffuse.X = value.R;
                directionalLight1Diffuse.Y = value.G;
                directionalLight1Diffuse.Z = value.B;
            }
        }

        public float DirectionalLight1DiffuseIntensity
        {
            get { return directionalLight1Diffuse.W; }
            set { directionalLight1Diffuse.W = value; }
        }

        public Color DirectionalLight1SpecularColor
        {
            get { return new Color(directionalLight1Specular.X, directionalLight1Specular.Y, directionalLight1Specular.Z); }
            set
            {
                directionalLight1Specular.X = value.R;
                directionalLight1Specular.Y = value.G;
                directionalLight1Specular.Z = value.B;
            }
        }

        public float DirectionalLight1SpecularIntensity
        {
            get { return directionalLight1Specular.W; }
            set { directionalLight1Specular.W = value; }
        }

        public Vector3 DirectionalLight2Direction
        {
            get { return directionalLight2Direction; }
            set { directionalLight2Direction = value; }
        }

        public Color DirectionalLight2DiffuseColor
        {
            get { return new Color(directionalLight2Diffuse.X, directionalLight2Diffuse.Y, directionalLight2Diffuse.Z); }
            set
            {
                directionalLight2Diffuse.X = value.R;
                directionalLight2Diffuse.Y = value.G;
                directionalLight2Diffuse.Z = value.B;
            }
        }

        public float DirectionalLight2DiffuseIntensity
        {
            get { return directionalLight2Diffuse.W; }
            set { directionalLight2Diffuse.W = value; }
        }

        public Color DirectionalLight2SpecularColor
        {
            get { return new Color(directionalLight2Specular.X, directionalLight2Specular.Y, directionalLight2Specular.Z); }
            set
            {
                directionalLight2Specular.X = value.R;
                directionalLight2Specular.Y = value.G;
                directionalLight2Specular.Z = value.B;
            }
        }

        public float DirectionalLight2SpecularIntensity
        {
            get { return directionalLight2Specular.W; }
            set { directionalLight2Specular.W = value; }
        }

        public Vector3 DirectionalLight0Direction
        {
            get { return directionalLight0Direction; }
            set { directionalLight0Direction = value; }
        }

        public Color DirectionalLight0DiffuseColor
        {
            get { return new Color(directionalLight0Diffuse.X, directionalLight0Diffuse.Y, directionalLight0Diffuse.Z); }
            set
            {
                directionalLight0Diffuse.X = value.R;
                directionalLight0Diffuse.Y = value.G;
                directionalLight0Diffuse.Z = value.B;
            }
        }

        public float DirectionalLight0DiffuseIntensity
        {
            get { return directionalLight0Diffuse.W; }
            set { directionalLight0Diffuse.W = value; }
        }

        public Color DirectionalLight0SpecularColor
        {
            get { return new Color(directionalLight0Specular.X, directionalLight0Specular.Y, directionalLight0Specular.Z); }
            set
            {
                directionalLight0Specular.X = value.R;
                directionalLight0Specular.Y = value.G;
                directionalLight0Specular.Z = value.B;
            }
        }

        public float DirectionalLight0SpecularIntensity
        {
            get { return directionalLight0Specular.W; }
            set { directionalLight0Specular.W = value; }
        }

        #endregion

        #region matrix

        public Matrix[] Bones { get; set; }


        public Matrix World
        {
            get;
            set;
        }

        public Matrix View
        {
            get;
            set;
        }

        public Matrix Projection
        {
            get;
            set;
        }

        public Matrix WorldView
        { get { return World * View; } }

        public Matrix ViewProjection
        { get { return View * Projection; } }

        public Matrix WorldViewProjection
        { get { return World * View * Projection; } }

        #endregion

        #region color

        public Vector2 ColorMapOffset { get; set; }
        public Vector2 ColorMapTiles { get; set; }
        public Texture2D ColorMap
        {
            get;
            set;
        }

        public float Alpha
        {
            get;
            set;
        }

        #endregion

        #endregion

        #region ctor

        /// <summary>
        /// Constructs the CBasicEffect class with a default effect file ("Shaders/IntensityEffect").
        /// If you want to use this ctor, you have to create this effect file at this path.
        /// You also have to implement a technique named "SpecularLight" which will be the default technique.
        /// If you don't want to, use the second ctor.
        /// </summary>
        /// <param name="content">The content manager you want to use for this effect</param>
        public CEffect()
        {
            Alpha = 1;
            Brighteness = 50;
            if (ColorMap == null)
            {
                ColorMap = new Texture2D(CDare.Instance.GraphicsDevice, 1, 1);
                Color[] c = new Color[1] { Color.Red };
                ColorMap.SetData(c);
            }
            ColorMapTiles = Vector2.One;
            ColorMapTiles1 = Vector2.One;
            ColorMapTiles2 = Vector2.One;
            ColorMapTiles3 = Vector2.One;
            MultiTexturingMapTiles = Vector2.One;
            emissiveLight = new Vector4(1, 1, 1, 0);
            directionalLight1Diffuse = new Vector4(1, 1, 1, 0);
            directionalLight1Specular = new Vector4(1, 1, 1, 0);
            directionalLight2Diffuse = new Vector4(1, 1, 1, 0);
            directionalLight2Specular = new Vector4(1, 1, 1, 0);
            directionalLight0Diffuse = new Vector4(1, 1, 1, 0);
            directionalLight0Specular = new Vector4(1, 1, 1, 0);
            ambientLight = new Vector4(1, 1, 1, 0);
            UseSceneParameters = true;
            PerPixelLighteningEnabled = false;
            IsDecalsActive = false;
            IsMultiTexturingActive = false;
            DecalsProjectorMatrix = Matrix.Identity;
            if (DecalsMap == null)
            {
                DecalsMap = new Texture2D(CDare.Instance.GraphicsDevice, 1, 1);
                Color[] c = new Color[1] { new Color(0, 0, 0, 0) };
                DecalsMap.SetData(c);
            }
            /*DecalsProjectorPosition = Vector3.Zero;
            DecalsProjectorDirection = Vector3.Zero;
            DecalsProjectorSize = 1;
            DecalsProjectorUpVector = Vector3.UnitY;
            DecalsProjectorProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(90), 1, 1, 500);*/
        }

        public CEffect(CEffect _effect)
        {
            this.m_effect = _effect.m_effect;
            this.PerPixelLighteningEnabled = _effect.PerPixelLighteningEnabled;
            this.UseSceneParameters = _effect.UseSceneParameters;
            this.IsAnimationActive = _effect.IsAnimationActive;
            this.IsDecalsActive = _effect.IsDecalsActive;
            this.EyePosition = _effect.EyePosition;
            this.ColorMapTiles1 = _effect.ColorMapTiles1;
            this.ColorMapOffset1 = _effect.ColorMapOffset1;
            this.ColorMap1 = _effect.ColorMap1;
            this.ColorMapTiles2 = _effect.ColorMapTiles2;
            this.ColorMapOffset2 = _effect.ColorMapOffset2;
            this.ColorMap2 = _effect.ColorMap2;
            this.ColorMapTiles3 = _effect.ColorMapTiles3;
            this.ColorMapOffset3 = _effect.ColorMapOffset3;
            this.ColorMap3 = _effect.ColorMap3;
            this.MultiTexturingMapTiles = _effect.MultiTexturingMapTiles;
            this.MultiTexturingMapOffset = _effect.MultiTexturingMapOffset;
            this.MultiTexturingMap = _effect.MultiTexturingMap;
            this.DecalsProjectorMatrix = _effect.DecalsProjectorMatrix;
            this.DecalsMap = _effect.DecalsMap;
            this.Brighteness = _effect.Brighteness;
            this.LighteningEnabled = _effect.LighteningEnabled;
            this.AmbientLightColor = _effect.AmbientLightColor;
            this.EmissiveLightColor = _effect.EmissiveLightColor;
            this.EmissiveLightIntensity = _effect.EmissiveLightIntensity;

            this.DirectionalLight0Direction = _effect.DirectionalLight0Direction;
            this.DirectionalLight0DiffuseColor = _effect.DirectionalLight0DiffuseColor;
            this.DirectionalLight0DiffuseIntensity = _effect.DirectionalLight0DiffuseIntensity;
            this.DirectionalLight0SpecularColor = _effect.DirectionalLight0SpecularColor;
            this.DirectionalLight0SpecularIntensity = _effect.DirectionalLight0SpecularIntensity;

            this.DirectionalLight1Direction = _effect.DirectionalLight1Direction;
            this.DirectionalLight1DiffuseColor = _effect.DirectionalLight1DiffuseColor;
            this.DirectionalLight1DiffuseIntensity = _effect.DirectionalLight1DiffuseIntensity;
            this.DirectionalLight1SpecularColor = _effect.DirectionalLight1SpecularColor;
            this.DirectionalLight1SpecularIntensity = _effect.DirectionalLight1SpecularIntensity;

            this.DirectionalLight2Direction = _effect.DirectionalLight2Direction;
            this.DirectionalLight2DiffuseColor = _effect.DirectionalLight2DiffuseColor;
            this.DirectionalLight2DiffuseIntensity = _effect.DirectionalLight2DiffuseIntensity;
            this.DirectionalLight2SpecularColor = _effect.DirectionalLight2SpecularColor;
            this.DirectionalLight2SpecularIntensity = _effect.DirectionalLight2SpecularIntensity;

            this.World = _effect.World;
            this.View = _effect.View;
            this.Projection = _effect.Projection;
            this.Bones = _effect.Bones;
            this.ColorMapOffset = _effect.ColorMapOffset;
            this.ColorMapTiles = _effect.ColorMapTiles;
            this.ColorMap = _effect.ColorMap;
            this.Alpha = _effect.Alpha;
        }

        #endregion

        #region Method

        public CEffect Clone()
        {
            CEffect e = new CEffect();

            e.lighteningEnabled = lighteningEnabled;
            e.emissiveLight = emissiveLight;
            e.ambientLight = ambientLight;
            e.directionalLight1Direction = directionalLight1Direction;
            e.directionalLight1Diffuse = directionalLight1Diffuse;
            e.directionalLight1Specular = directionalLight1Specular;
            e.directionalLight2Direction = directionalLight2Direction;
            e.directionalLight2Diffuse = directionalLight2Diffuse;
            e.directionalLight2Specular = directionalLight2Specular;
            e.directionalLight0Direction = directionalLight0Direction;
            e.directionalLight0Diffuse = directionalLight0Diffuse;
            e.directionalLight0Specular = directionalLight0Specular;
            e.m_effect = m_effect;

            e.PerPixelLighteningEnabled = PerPixelLighteningEnabled;
            e.UseSceneParameters = UseSceneParameters;
            e.IsAnimationActive = IsAnimationActive;
            e.IsDecalsActive = IsDecalsActive;
            e.EyePosition = EyePosition;
            e.IsMultiTexturingActive = IsMultiTexturingActive;

            e.ColorMapTiles1 = ColorMapTiles1;
            e.ColorMapOffset1 = ColorMapOffset1;
            e.ColorMap1 = ColorMap1;
            e.ColorMapTiles2 = ColorMapTiles2;
            e.ColorMapOffset2 = ColorMapOffset2;
            e.ColorMap2 = ColorMap2;
            e.ColorMapTiles3 = ColorMapTiles3;
            e.ColorMapOffset3 = ColorMapOffset3;
            e.ColorMap3 = ColorMap3;
            e.MultiTexturingMapTiles = MultiTexturingMapTiles;
            e.MultiTexturingMapOffset = MultiTexturingMapOffset;
            e.MultiTexturingMap = MultiTexturingMap;

            e.DecalsProjectorMatrix = DecalsProjectorMatrix;
            e.DecalsMap = DecalsMap;

            e.Brighteness = Brighteness;

            e.Bones = Bones;
            e.World = World;
            e.View = View;

            e.Projection = Projection;

            e.ColorMapOffset = ColorMapOffset;
            e.ColorMapTiles = ColorMapTiles;
            e.ColorMap = ColorMap;

            e.Alpha = Alpha;
            return e;
        }

        public virtual void ProcessEffect(CRender3D render)
        {
            if (IsAnimationActive)
            {
                if (IsDecalsActive)
                    m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.DECALSSKINNED);
                else
                    m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.SKINNED);
            }
            else if (IsMultiTexturingActive)
            {
                if (IsDecalsActive)
                    m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.DECALSMULTITEXTURING);
                else
                    m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.MULTITEXTURING);
            }
            else if (IsDecalsActive)
                m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.DECALS);
            else
                m_effect = render.EffectMgr.GetEffect(CEffectMgr.EEffectType.BASIC);
            EyePosition = render.CameraMgr.ActiveCamera.Position;
            View = render.CameraMgr.ActiveCamera.View;
            Projection = render.CameraMgr.ActiveCamera.Projection;
            m_effect.ProcessEffect(render, this);
        }

        #endregion
    }
}
